#include "utils.h"
#include <signal.h>

socklen_t client_addr_len;        // 客户端地址长度
struct sockaddr_in client_addrin; // 客户端地址结构体
int client_fd;                    // 客户端套接字

// UDP数据包结构体
typedef struct UDP_data
{
    char time[15];  // 时间
    int SYN;        // 请求类型
    int room_id;    // 聊天室ID
    char name[31];  // 用户名字
    char data[1024]; // 消息内容
} UDP_data;

UDP_data client_data; // 客户端数据包
int running = 1;      // 用于控制线程运行的标志

// 初始化客户端
int UDP_Init_Client(in_port_t port, const char *s_addr)
{
    int client_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (client_fd == -1)
    {
        perror("socket error");
        exit(-1);
    }

    client_addrin.sin_family = AF_INET;                // 地址族
    client_addrin.sin_port = htons(port);              // 端口号
    client_addrin.sin_addr.s_addr = inet_addr(s_addr); // IP地址
    client_addr_len = sizeof(client_addrin);           // 结构体大小
    return client_fd;
}

// 清理输入缓冲区（防止`fgets`读取残留的换行符）
void clear_input_buffer()
{
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

// 处理信号（例如 Ctrl+C）以优雅退出
void handle_signal(int sig)
{
    if (sig == SIGINT)
    {
        // printf("%s\n成功退出群聊!%s\n", YELLOW, RESET);
        // 通知服务器退出聊天室
        client_data.SYN = 3;                                            // SYN=3 表示退出聊天室
        sprintf(client_data.data, "%s 已退出聊天室", client_data.name); // 发送退出消息
        sendto(client_fd, &client_data, sizeof(client_data), 0, (struct sockaddr *)&client_addrin, client_addr_len);

        running = 0; // 停止接收和发送线程
        close(client_fd);
        exit(0);
    }
}

// 发送消息的线程
void *write_pthread(void *sock)
{
    int client_fd = *((int *)sock);
    memset(&client_data, 0, sizeof(client_data)); // 初始化客户端数据包

    // 请求聊天室列表
    client_data.SYN = 0; // SYN=0 表示请求聊天室列表
    sendto(client_fd, &client_data, sizeof(client_data), 0, (struct sockaddr *)&client_addrin, client_addr_len);

    // 等待服务器返回列表
    sleep(1); // 可以通过更好的同步机制代替，例如条件变量

    // 用户选择操作
    printf("%s选择操作: 1-加入聊天室\t2-创建新聊天室\n%s", GREEN, RESET);
    int choice;
    scanf("%d", &choice);
    clear_input_buffer(); // 清理输入缓冲区，防止`fgets`读取到之前的输入残留

    if (choice == 1)
    { // 加入聊天室
        printf("请输入要加入的聊天室ID: ");
        scanf("%d", &client_data.room_id);
        clear_input_buffer(); // 清理输入缓冲区
        client_data.SYN = 1;  // SYN=1 表示加入聊天室
        printf("请输入你的名字: ");
        scanf("%s", client_data.name);
        sendto(client_fd, &client_data, sizeof(client_data), 0, (struct sockaddr *)&client_addrin, client_addr_len);
    }
    else if (choice == 2)
    { // 创建新聊天室
        printf("请输入聊天室名称: ");
        fgets(client_data.data, sizeof(client_data.data), stdin);
        client_data.data[strcspn(client_data.data, "\n")] = 0; // 去掉换行符
        client_data.SYN = 4;                                   // SYN=4 表示创建聊天室
        printf("请输入你的名字: ");
        scanf("%s", client_data.name);
        clear_input_buffer(); // 清理输入缓冲区
        sendto(client_fd, &client_data, sizeof(client_data), 0, (struct sockaddr *)&client_addrin, client_addr_len);
    }
    else
    {
        printf("无效选择。\n");
        running = 0; // 如果选择无效，退出程序
        return NULL;
    }

    // 循环发送消息
    printf("输入消息（或输入 'quit' 退出聊天室）\n");
    while (running)
    {
        fgets(client_data.data, sizeof(client_data.data), stdin);
        client_data.data[strcspn(client_data.data, "\n")] = 0;                   // 去掉换行符
        printf("%s%s:%s%s\n", GREEN, client_data.name, client_data.data, RESET); // 显示发送消息

        if (strcmp(client_data.data, "quit") == 0)
        {
            client_data.SYN = 3;                                            // SYN=3 表示退出
            sprintf(client_data.data, "%s 已退出聊天室", client_data.name); // 发送退出消息
            sendto(client_fd, &client_data, sizeof(client_data), 0, (struct sockaddr *)&client_addrin, client_addr_len);
            running = 0; // 设置线程退出标志
            break;
        }
        else
        {
            client_data.SYN = 2; // SYN=2 表示聊天消息
            sendto(client_fd, &client_data, sizeof(client_data), 0, (struct sockaddr *)&client_addrin, client_addr_len);
        }
    }

    return NULL;
}

// 接收消息的线程
void *read_pthread(void *sock)
{
    int client_fd = *((int *)sock);
    UDP_data server_response; // 服务器响应数据包

    while (running)
    {
        memset(&server_response, 0, sizeof(server_response)); // 清空响应
        recvfrom(client_fd, &server_response, sizeof(server_response), 0, NULL, NULL);

        // 根据SYN类型来判断处理的消息类型
        if (server_response.SYN == 0)
        {
            // SYN=0 表示聊天室列表
            printf("%s\n", server_response.data);
        }
        else if (server_response.SYN == 1)
        {
            printf("%s\n", server_response.data);          // 处理加入聊天室等信息
            client_data.room_id = server_response.room_id; // 更新客户端的room_id
        }
        else if (server_response.SYN == 3)
        {
            // SYN=3 表示有用户退出
            printf("\n%s%s已经退出聊天室%d!%s\n", RED, server_response.name, server_response.room_id, RESET);
        }
        // 检查消息的聊天室ID，确保消息只显示在正确的聊天室
        if (server_response.room_id == client_data.room_id)
        { // 确保是同一聊天室
            if (server_response.SYN == 2)
            {
                // SYN=2 表示聊天消息，跳过显示自己的消息
                if (strcmp(server_response.name, client_data.name) != 0)
                {
                    printf("%s:%s\n", server_response.name, server_response.data);
                }
            }
        }
    }

    return NULL;
}

int main(int argc, char *argv[])
{
    signal(SIGINT, handle_signal); // 注册信号处理函数，捕获 Ctrl+C 等信号

    client_fd = UDP_Init_Client(8888, "192.168.10.4"); // 初始化客户端
    // 启动发送和接收线程
    pthread_t write_thread, read_thread;                            // 线程ID
    pthread_create(&write_thread, NULL, write_pthread, &client_fd); // 创建发送线程
    pthread_create(&read_thread, NULL, read_pthread, &client_fd);   // 创建接收线程

    pthread_join(write_thread, NULL); // 等待发送线程结束
    pthread_join(read_thread, NULL);  // 等待接收线程结束
    close(client_fd);                 // 关闭客户端文件描述符
    return 0;
}
